package com.sfx.concurrent.demo.cas.unsafe;
import cn.hutool.core.thread.ThreadUtil;
import sun.misc.Unsafe;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

import static com.sfx.concurrent.demo.concurrent.AtomicTest.MyUnSafe.UnSafeAccessor.getUnsafe;

public class TestCompareAndSwap {
    // 基于CAS无锁实现的安全自增
    static class OptimisticLockingPlus {
        //并发数量
        private static final int THREAD_COUNT = 10;
        //内部值，使用volatile保证线程可见性
        private volatile int value;//值
        //不安全类
        private static final Unsafe unsafe = getUnsafe();
        ;
        //value 的内存偏移（相对于对象头部的偏移，不是绝对偏移）
        private static final long valueOffset;
        //统计失败的次数
        private static final AtomicLong failure = new AtomicLong(0);

        static {
            try {
                //取得value属性的内存偏移
                valueOffset = unsafe.objectFieldOffset(
                        OptimisticLockingPlus.class.getDeclaredField("value"));
                System.out.println("valueOffset:=" + valueOffset);
            } catch (Exception ex) {
                throw new Error(ex);
            }
        }

        //通过CAS原子操作，进行“比较并交换”
        public final boolean unSafeCompareAndSet(int oldValue, int newValue) {
            //原子操作：使用unsafe的“比较并交换”方法进行value属性的交换
            return unsafe.compareAndSwapInt(
                    this, valueOffset, oldValue, newValue);
        }

        //使用无锁编程实现安全的自增方法
        public void selfPlus() {
            int oldValue = value;
            //通过CAS原子操作，如果操作失败就自旋，一直到操作成功
            int i = 0;
            do {
            // 获取旧值
                oldValue = value;
                  //统计无效的自旋次数
                if (i++ > 1) {
                    //记录失败的次数
                    failure.incrementAndGet();
                }
            } while (!unSafeCompareAndSet(oldValue, oldValue + 1));
        }

        //测试用例入口方法
        public static void main(String[] args) throws InterruptedException {
            final OptimisticLockingPlus cas = new OptimisticLockingPlus();
            //倒数闩，需要倒数THREAD_COUNT次

            CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
            for (int i = 0; i < THREAD_COUNT; i++) {
                 // 提交10个任务
                Executors.newFixedThreadPool(10).submit(() ->
                {
                    //每个任务累加1000次
                    for (int j = 0; j < 1000; j++) {
                        cas.selfPlus();
                    }
                    latch.countDown(); // 执行完一个任务，倒数闩减少一次
                });
            }
            latch.await(); //主线程等待倒数闩倒数完毕
            System.out.println("累加之和：" + cas.value);
            System.out.println("失败次数：" + cas.failure.get());
        }
    }
}